/**
 * Author(s): xuming.Wong <xuming.Wong@gmail.com>
 */
#include "NetInputStream.h"

namespace PQNet
{
	NetInputStream::NetInputStream(PQNet::TCPSocket* sock,int bufferSize,int maxBufferSize)
		: _socket(sock),_bufferSize(bufferSize),_maxBufferSize(maxBufferSize),
		_head(0),_tail(0)
	{
		_buffer=new char[_bufferSize];
		memset(_buffer, 0, _bufferSize);

	}

	NetInputStream::~NetInputStream()
	{
		SAFE_DELETE_ARRAY(_buffer);
	}


	int NetInputStream::fill()
	{
		int nFilled=0;
		int nReceived=0;
		int nFree=0;

		if(_head<=_tail){
		}else{//head>tail
			nReceived=0;
			nFree=_bufferSize-_tail;//
			nReceived=_socket->receive(_buffer+_tail,nFree);
			if(nReceived==SOCKET_ERROR||nReceived==0){
				return nReceived;
			}
			_tail=(_tail+nReceived)%_bufferSize;//circular
			nFilled+=nReceived;
			if(nReceived==nFree){
				nReceived=0;
				nFree=_head-1;
				if(nFree!=0){
					nReceived=_socket->receive(_buffer,nFree);
					if(nReceived==SOCKET_ERROR||nReceived==0){
						return nReceived;
					}
					_tail+=nReceived;
					nFilled+=nReceived;
				}
				if(nReceived==nFree){
					int available=_socket->available();
					if(available>0){
						if((_bufferSize+available+1)>_maxBufferSize){
							initBuffer();
							return -1;//buffer overflow
						}

						if(!resize(available+1)){
							return 0;
						}

						nReceived=_socket->receive(_buffer+_tail,available);

						if(nReceived==SOCKET_ERROR||nReceived==0){
							return nReceived;
						}

						_tail+=nReceived;
						nFilled+=nReceived;

					}

				}

			}
		}
		return 0;
		/*
		__ENTER_FUNCTION_FOXNET

	UINT nFilled = 0 ;
	UINT nReceived = 0 ;
	UINT nFree = 0 ;

	if ( m_Head <= m_Tail ) 
	{
		if ( m_Head == 0 ) 
		{
			//
			// H   T		LEN=10
			// 0123456789
			// abcd......
			//

			nReceived = 0 ;
			nFree = m_BufferLen-m_Tail-1 ;
			if( nFree != 0 )
			{
				nReceived = m_pSocket->receive( &m_Buffer[m_Tail] , nFree );
				if (nReceived==SOCKET_ERROR_WOULDBLOCK) return 0 ; 
				if (nReceived==SOCKET_ERROR) return SOCKET_ERROR-1 ;
				if (nReceived==0) return SOCKET_ERROR-2 ;

				m_Tail += nReceived;
				nFilled += nReceived;
			}

			if( nReceived == nFree ) 
			{
				UINT available = m_pSocket->available();
				if ( available > 0 ) 
				{
					if( (m_BufferLen+available+1)>m_MaxBufferLen )
					{
						Initsize( ) ;
						return SOCKET_ERROR-3 ;
					}
					if( !Resize( available+1 ) )
						return 0 ;

					nReceived = m_pSocket->receive( &m_Buffer[m_Tail] , available );
					if (nReceived==SOCKET_ERROR_WOULDBLOCK) return 0 ; 
					if (nReceived==SOCKET_ERROR) return SOCKET_ERROR-4 ;
					if (nReceived==0) return SOCKET_ERROR-5;

					m_Tail += nReceived;
					nFilled += nReceived;
				}
			}
		} 
		else 
		{
			//
			//    H   T		LEN=10
			// 0123456789
			// ...abcd...
			//

			
		}

	} 
	else 
	{	
		//
        //     T  H		LEN=10
        // 0123456789
        // abcd...efg
        //

		nReceived = 0 ;
		nFree = m_Head-m_Tail-1 ;
		if( nFree!=0 )
		{
			nReceived = m_pSocket->receive( &m_Buffer[m_Tail], nFree ) ;
			if( nReceived==SOCKET_ERROR_WOULDBLOCK ) return 0 ; 
			if( nReceived==SOCKET_ERROR ) return SOCKET_ERROR-13 ;
			if( nReceived==0 ) return SOCKET_ERROR-14 ;

			m_Tail += nReceived ;
			nFilled += nReceived ;
		}
		if( nReceived==nFree ) 
		{
			UINT available = m_pSocket->available( ) ;
			if ( available>0 ) 
			{
				if( (m_BufferLen+available+1)>m_MaxBufferLen )
				{
					Initsize( ) ;
					return SOCKET_ERROR-15 ;
				}
				if( !Resize( available+1 ) )
					return 0 ;

				nReceived = m_pSocket->receive( &m_Buffer[m_Tail], available ) ;
				if( nReceived==SOCKET_ERROR_WOULDBLOCK ) return 0 ; 
				if( nReceived==SOCKET_ERROR ) return SOCKET_ERROR-16 ;
				if( nReceived==0 ) return SOCKET_ERROR-17 ;

				m_Tail += nReceived ;
				nFilled += nReceived ;
			}
		}
	}

	return nFilled ;

__LEAVE_FUNCTION_FOXNET

	return 0 ;
	*/
	}


	void NetInputStream::initBuffer()
	{
		_head=_tail=0;
		SAFE_DELETE_ARRAY(_buffer);
		_buffer=new char[NET_INPUT_SIZE_DEFAULT];
		_bufferSize=NET_INPUT_SIZE_DEFAULT;
		memset(_buffer,0,_bufferSize);

	}

	int NetInputStream::length( ) const
	{
		if(_head<_tail ){
			return _tail-_head;
		}else if(_head>_tail){
			return _bufferSize-_head+_tail;
		}
		return 0;

	}

	bool NetInputStream::resize(int size)
	{
		int realSize=max(size,(int)(_bufferSize>>1));
		int newSize=_bufferSize+realSize;
		int  len=length();

		if(realSize<0){
			if(newSize<0 || newSize<len){
				return false;
			}
		}
		char* buffer=new char[newSize];
		if(_head<_tail){
			memcpy(_buffer,_buffer+_head,_tail-_head);
		}else if(_head>_tail){
			memcpy(_buffer,_buffer+_head,_bufferSize-_head);
			memcpy(_buffer+_bufferSize-_head,_buffer,_tail);
		}

		delete [] _buffer ;

		_buffer = buffer ;
		_bufferSize = newSize ;
		_head = 0 ;
		_tail = len ;

		return true;
	}

}
